// i.r(t), i.d(t, { default: () => ModelDataModule })
import Module from "./Module"
import SettingsModule from "./SettingsModule"
import ApiClientModule, { Api } from "./ApiClientModule"
import Logger from "../utils/Logger"
import paramsUtil from "../utils/params.util"
const u = new Logger("modelurls")
class UrlContainerNoop {
  version: number
  baseUrl: string
  expires: number
  constructor(...e) {
    this.version = 3
    this.baseUrl = ""
    this.expires = 0
  }
  validate(_e) {
    return !0
  }
  update(_e) {
    return Promise.resolve()
  }
  get(e) {
    if (!this.isSigned(e)) throw new Error("Tried getting relative model url with no signed urls configured.")
    return e
  }
  isSigned(e) {
    if (!e.match(/^https?:/)) return !1
    const t = e.indexOf("?")
    if (-1 === t) return !1
    return new URLSearchParams(e.substr(t)).has("t")
  }
}
//附件,模型数据地址,彭蔚
class UrlContainerV3 extends UrlContainerNoop {
  absoluteUrl: string
  constructor() {
    super(...arguments), (this.version = 3), (this.baseUrl = ""), (this.absoluteUrl = ""), (this.expires = 0)
  }
  validate(e) {
    // return (
    //   e.templates &&
    //   e.catalog_file &&
    //   (!e.expires || 1000 * e.expires > Date.now())
    // )
    return true
  }
  update(e) {
    if (!e.templates) throw new Error("No templates found.")
    return (
      (this.baseUrl = e.templates[0]),
      (this.absoluteUrl = this.baseUrl.split("{{filename}}").shift() || ""),
      e.expires ? (this.expires = 1000 * e.expires) : (this.expires = Date.now() + 240000),
      Promise.resolve()
    )
  }
  get(e) {
    return this.baseUrl && this.baseUrl.replace("{{filename}}", e.replace(this.absoluteUrl, ""))
  }
}
class ModelUrls {
  api: Api
  endpoint: any
  urlContainer: any
  previousRefreshPromise: any
  containerClasses: typeof UrlContainerNoop[]
  meshUrls: string
  constructor(e, t) {
    this.api = e
    this.endpoint = t
    this.urlContainer = null
    this.previousRefreshPromise = null
    this.containerClasses = [UrlContainerNoop]
    t ? (this.containerClasses = [UrlContainerV3]) : (this.urlContainer = new UrlContainerNoop())
  }
  needsRefresh() {
    if (null === this.endpoint) return !1
    const e = this.urlContainer ? this.urlContainer.expires : Date.now()
    return Date.now() + 15000 > e
  }
  refresh() {
    if (!this.needsRefresh()) return Promise.resolve()
    if (!this.previousRefreshPromise) {
      u.debug("Refreshing urls...")
      const e = this
      this.previousRefreshPromise = this._refresh().then(
        function () {
          u.debug("Refreshed"), (e.previousRefreshPromise = null)
        },
        function (t) {
          u.error("Failed url refresh, urls might go stale soon", t), (e.previousRefreshPromise = null)
        }
      )
    }
    return this.previousRefreshPromise
  }
  async _refresh(e = !0) {
    const t = this.endpoint
      ? await this.api.get(this.endpoint, {
          responseType: "json",
          prefetchFrom: e ? "files" : void 0,
          priority: httpPriority.HIGHEST
        })
      : null
    if (this.urlContainer && this.urlContainer.validate(t)) return this.urlContainer.update(t)
    for (const e of this.containerClasses) {
      const i = new e()
      if (i.validate(t)) return u.info("Using urls version " + i.version), (this.urlContainer = i), this.urlContainer.update(t)
    }
    if (e) return this._refresh(!1)
    throw new Error("missing-urls")
  }
  isSigned(e) {
    var t
    return (null === (t = this.urlContainer) || void 0 === t ? void 0 : t.isSigned(e)) || !1
  }
  async getSignedUrl(e) {
    if ((await this.refresh(), !this.urlContainer)) throw new Error("Tried to use ModelUrls.get before urlContainer is established.")
    const t = this.urlContainer.get(e)
    if (!t) throw new Error(`Could not get signed URL for path ${e}`)
    return t
  }
  getSignedUrlSync(e) {
    if ((this.refresh(), !this.urlContainer)) throw new Error("Tried to use ModelUrls.get before urlContainer is established.")
    const t = this.urlContainer.get(e)
    if (!t) throw new Error(`Could not get signed URL for path ${e}`)
    return t
  }
  async getFile(e, t, i) {
    const n = this.isSigned(e) ? e : await this.getSignedUrl(e),
      s = paramsUtil.addParams(n, i)
    return this.api.getOnStoreQueue(s, t)
  }
  async getImage(e, t?, i?) {
    const n = this.isSigned(e) ? e : await this.getSignedUrl(e),
      s = paramsUtil.addParams(n, i)
    return this.api.getImage(s, t)
  }
  async getImageBitmap(e, t, i, n, s?) {
    const r = this.isSigned(e) ? e : await this.getSignedUrl(e),
      o = paramsUtil.addParams(r, s)
    return this.api.getImageBitmap(o, t, i, n)
  }
}

import ExpiringResource, { setOnStateFunc } from "../utils/ExpiringResource"
import ModelData from "../data/ModelData"

export class Model {
  lastPublished: string
  meshUrls: any[]
  sid: string
  uuid: string
  image: string
  organizationId: string
  details: {
    sid: string
    name: string
    presentedBy: any
    summary: any
    formattedAddress: string
    contact: { email: string; name: string; phone: string; formattedPhone: string }
    externalUrl: string
  }
  options: { urlBranding: boolean; socialSharing: boolean; isPublic: boolean; isVR: boolean }
  textures: ExpiringResource[]
  constructor() {
    this.lastPublished = null
  }
  refresh(e) {
    for (const t in this.textures) e.textures[t] && this.textures[t].refreshFrom(e.textures[t])
    this.meshUrls.forEach((t, i) => {
      const n = e.meshUrls[i] && e.meshUrls[i].url
      t.url && n && t.url.refreshFrom(n)
    })
  }
}
import { NotImplementedError } from "../exception/store.exception"
import MpWebStore from "../storage/MpWebStore"
import PrefetchedData from "../utils/PrefetchedData"

class MpWebModelDeserializer {
  deserialize(e) {
    var t
    const i = new Model()
    i.sid = e.sid
    i.uuid = e.job.uuid
    i.image = e.icon || ""
    i.organizationId = e.owner?.group_sid
    i.details = {
      sid: e.sid,
      name: e.name,
      presentedBy: e.presented_by,
      summary: e.summary,
      formattedAddress: this.formatAddress(e.address),
      contact: {
        email: e.contact_email,
        name: e.contact_name,
        phone: e.contact_phone,
        formattedPhone: e.formatted_contact_phone
      },
      externalUrl: e.external_url
    }
    i.options = {
      urlBranding: !0,
      socialSharing: !!e.enable_social_sharing,
      isPublic: !!e.is_public,
      isVR: !!e.is_vr
    }
    return i
  }
  formatAddress(e) {
    if ("string" == typeof e)
      try {
        e = JSON.parse(e)
      } catch (e) {
        return ""
      }
    if (!(e && (e.address_1 || e.address_2 || e.city || e.state || e.zip))) return ""
    const t = []
    return (
      e.address_1 && t.push(e.address_1),
      e.address_2 && t.push(e.address_2),
      e.city && (t.length > 0 && t.push(", "), t.push(e.city)),
      e.state && (t.length > 0 && t.push(", "), t.push(e.state)),
      e.zip && (t.length > 0 && t.push(", "), t.push(e.zip)),
      t.join("")
    )
  }
}
class MpWebModelStore extends MpWebStore {
  deserializer: MpWebModelDeserializer

  constructor(e) {
    super(e), (this.deserializer = new MpWebModelDeserializer())
  }
  async read() {
    const { modelId } = this.config
    // t = `/api/v1/player/models/${e}/`
    const url = `/scene-portal/api/v1/player/models/${modelId}`

    const data = PrefetchedData.model ? PrefetchedData.model : await this.request(httpEnum.GET, url)
    return this.deserializer.deserialize(data)
  }
  async refresh() {
    throw new NotImplementedError("Model refresh not implemented")
  }
}
import funcUtil from "../utils/func.util"
import httpEnum, { httpPriority } from "../enum/http.enum"
import keyConst from "../constant/key.const"
import storageTypeEnum from "../enum/storageType.enum"
import { ModelDataLoadedMessage } from "../message/model.message"
const O = new Logger("model-data")
export default class ModelDataModule extends Module {
  engine: any
  store: any
  model: any
  signedUrls: ModelUrls
  constructor() {
    super(...arguments), (this.name = "model-data")
  }
  async init(e, t) {
    this.engine = t
    const { modelId: i, baseUrl: n } = e
    this.store = this.getStore(e)
    const [s, l] = await Promise.all([this.store.read(), t.getModule(ApiClientModule)])
    if (!s) throw Error("Could not fetch model data")
    setOnStateFunc(s, async () => {
      const e = await this.store.refresh()
      s.refresh(e)
    }),
      (this.model = s)
    const c = new ModelData(this.model)
    t.market.register(this, ModelData, c)
    this.registerSettings(c)
    const h = l.getApi()
    const d = `${n}/scene-portal/api/player/models/${i}/files?type=3${e.privledgedSignedUrls ? "&acl=1" : ""}`
    this.signedUrls = new ModelUrls(h, d)
    this.signedUrls.meshUrls = this.model.meshUrls
    t.broadcast(new ModelDataLoadedMessage(this.signedUrls, this.model.sid, this.model.vrSupported))
  }
  async registerSettings(e) {
    const t = await this.engine.getModule(SettingsModule),
      i = "Model Options",
      { urlBranding: n = !0, socialSharing: r, isPublic: o, isVR: a } = e.model.options || {}
    t.registerSetting(keyConst.socialSharing, r)
    t.registerSetting("is_public", o)
    t.registerSetting("is_vr", a)
    const l = !n || !!funcUtil.getUrlParams("brand", !0)
    const c = n ? funcUtil.getUrlParams("mls", "0") : "0"
    const h = n ? funcUtil.getUrlParams("title", "1") : "1"
    t.registerSetting(keyConst.about, "0" !== h && "2" !== c)
    t.registerSetting(keyConst.title, "0" !== h && "2" !== h)
    t.registerSetting(keyConst.brandingEnabled, l)
    t.registerSetting(keyConst.mlsMode, "1" === c || "2" === c)
  }
  getSignedUrls() {
    return this.signedUrls
  }
  getStore(e) {
    if (this.store) return this.store
    const { modelId: t, baseUrl: i, queue: n } = e,
      s = e.storageProvider || storageTypeEnum.JSONSTORE
    O.info(`Loading model details from ${s}`)
    return new MpWebModelStore({
      readonly: !0,
      modelId: t,
      baseUrl: i,
      queue: n
    })
  }
}
